<?php  
/*** Mongodb类** examples:   
* $mongo = new HMongodb("127.0.0.1:11223"); 
* $mongo->selectDb("test_db"); 
* 创建索引 
* $mongo->ensureIndex("test_table", array("id"=>1), array('unique'=>true)); 
* 获取表的记录 
* $mongo->count("test_table"); 
* 插入记录 
* $mongo->insert("test_table", array("id"=>2, "title"=>"asdqw")); 
* 更新记录 
* $mongo->update("test_table", array("id"=>1),array("id"=>1,"title"=>"bbb")); 
* 更新记录-存在时更新，不存在时添加-相当于set 
* $mongo->update("test_table", array("id"=>1),array("id"=>1,"title"=>"bbb"),array("upsert"=>1)); 
* 查找记录 
* $mongo->find("c", array("title"=>"asdqw"), array("start"=>2,"limit"=>2,"sort"=>array("id"=>1))) 
* 查找一条记录 
* $mongo->findOne("$mongo->findOne("ttt", array("id"=>1))", array("id"=>1)); 
* 删除记录 
* $mongo->remove("ttt", array("title"=>"bbb")); 
* 仅删除一条记录 
* $mongo->remove("ttt", array("title"=>"bbb"), array("justOne"=>1)); 
* 获取Mongo操作的错误信息 
* $mongo->getError(); 
*/  
  
class mongodbs {  
  
    //Mongodb连接  
    private $mongo;  
  
    var $curr_db_name;  
    var $curr_table_name;  
    var $error;
	
	
	
  
    /** 
    * 构造函数 
    * 支持传入多个mongo_server(1.一个出问题时连接其它的server 2.自动将查询均匀分发到不同server) 
    * 
    * 参数： 
    * $mongo_server:数组或字符串-array("127.0.0.1:1111", "127.0.0.1:2222")-"127.0.0.1:1111" 
    * $connect:初始化mongo对象时是否连接，默认连接 
    * $auto_balance:是否自动做负载均衡，默认是 
    * 
    * 返回值： 
    * 成功：mongo object 
    * 失败：false 
    */  
    function __construct($mongo_server="", $connect=true, $auto_balance=true)  
    {  
		
		if($this->mongo){
			return true;
		}
	
	
    	if (empty($mongo_server)){
    		$mongo_server=MongoHost;
    	}
        if (is_array($mongo_server))  
        {  
            $mongo_server_num = count($mongo_server);  
            if ($mongo_server_num > 1 && $auto_balance)  
            {  
                $prior_server_num = rand(1, $mongo_server_num);  
                $rand_keys = array_rand($mongo_server,$mongo_server_num);  
                $mongo_server_str = $mongo_server[$prior_server_num-1];  
                foreach ($rand_keys as $key)  
                {  
                    if ($key != $prior_server_num - 1)  
                    {  
                        $mongo_server_str .= ',' . $mongo_server[$key];  
                    }  
                }  
            }  
            else  
            {  
                $mongo_server_str = implode(',', $mongo_server);  
            }                  }  
        else  
        {  
            $mongo_server_str = $mongo_server;  
        }  
        try {  
            $this->mongo = new MongoDB\Driver\Manager("mongodb://".$mongo_server_str);
        }  
        catch (MongoConnectionException $e)  
        {  
            $this->error = $e->getMessage();  
            return false;  
        }  
    }  
  
    function getInstance($mongo_server, $flag=array())  
    {  
        static $mongodb_arr;  
        if (emptyempty($flag['tag']))  
        {  
            $flag['tag'] = 'default';          }  
        if (isset($flag['force']) && $flag['force'] == true)  
        {  
            $mongo = new HMongodb($mongo_server);  
            if (emptyempty($mongodb_arr[$flag['tag']]))  
            {  
                $mongodb_arr[$flag['tag']] = $mongo;  
            }  
            return $mongo;  
        }  
        else if (isset($mongodb_arr[$flag['tag']]) && is_resource($mongodb_arr[$flag['tag']]))  
        {  
            return $mongodb_arr[$flag['tag']];  
        }  
        else  
        {  
            $mongo = new HMongodb($mongo_server);  
            $mongodb_arr[$flag['tag']] = $mongo;  
            return $mongo;                  }          }  
  
    /** 
    * 连接mongodb server 
    * 
    * 参数：无 
    * 
    * 返回值： 
    * 成功：true 
    * 失败：false 
    */  
    function connect()  
    {  
        try {  
            $this->mongo->connect();  
            return true;  
        }  
        catch (MongoConnectionException $e)  
        {  
            $this->error = $e->getMessage();  
            return false;  
        }  
    }  
  
    /** 
    * select db 
    * 
    * 参数：$dbname 
    * 
    * 返回值：无 
    */  
    function selectDb($dbname)  
    {  
        $this->curr_db_name = $dbname;  
    }  
  
    /** 
    * 创建索引：如索引已存在，则返回。 
    * 
    * 参数： 
    * $table_name:表名 
    * $index:索引-array("id"=>1)-在id字段建立升序索引 
    * $index_param:其它条件-是否唯一索引等 
    * 
    * 返回值： 
    * 成功：true 
    * 失败：false 
    */  
    function ensureIndex($table_name, $index, $index_param=array())  
    {  
        $dbname = $this->curr_db_name;  
        $index_param['safe'] = 1;  
        try {  
            $this->mongo->$dbname->$table_name->ensureIndex($index, $index_param);  
            return true;  
        }  
        catch (MongoCursorException $e)  
        {  
            $this->error = $e->getMessage();  
            return false;  
        }  
    }  
  
    /** 
    * 插入记录 
    * 
    * 参数： 
    * $table_name:表名 
    * $record:记录 
    * 
    * 返回值： 
    * 成功：true 
    * 失败：false 
    */  
    function insert($table_name, $record)  
    {  

        $dbname = $this->curr_db_name;  
        try {  
			$bulk = new MongoDB\Driver\BulkWrite;
            $bulk->insert($record);
			
			$res=$this->mongo->executeBulkWrite($dbname.'.'.$table_name, $bulk);
			//自动创建索引
           // $this->atuoEnsuIndex($table_name,$record);
            return true;  
        }  
        catch (MongoCursorException $e)  
        {  
            $this->error = $e->getMessage();  
            return false;  
        }  
    }  
  
    /** 
    * 查询表的记录数 
    * 
    * 参数： 
    * $table_name:表名 
    * 
    * 返回值：表的记录数 
    */  
    function count($table_name,$where=array())  
    {  
        $dbname = $this->curr_db_name;  
		$cmd = new MongoDB\Driver\Command([
    		'count' => $table_name, 
    		'query' => $where 
		]);
		$cursor = $this->mongo->executeCommand($dbname, $cmd);
		$response = $cursor->toArray()[0];
		//var_dump($response);
		return $response->n;
    	
    }
    
    /**
     * 聚合查询
     *
     * 参数：
     * $table_name:表名
     *
     * 返回值：表的记录数
     */
    function sum(string $table_name,string $sumField, array $where=array())
    {
     	 try{
     	 	if (!$where){
     	 		$where["_id"]=array('$ne' => null);
     	 	}
    		$dbname = $this->curr_db_name;
    		$commands = new MongoDB\Driver\Command([
    				'aggregate' => $table_name,
    				'pipeline' => [
    					['$match'=>$where],
        				['$group' => ['_id' => '$hid', 'sum' => ['$sum' => '$'.$sumField]]],
    				],
    				'cursor' => new stdClass,
			 ]);
			$cursor = $this->mongo->executeCommand($dbname, $commands);
			$sums=0;
			foreach ($cursor as $document) {
				$array=$this->object2array($document);
				if ($array["sum"]){
					$sums=$array["sum"];
					
					break;
				}
			}
			return $sums;
			
    	}catch(Exception $e){
    		//无法连接数据库 异常处理
    		echo $e->getMessage();
    	}
    	
    }
  
    /** 
    * 更新记录 
    * 
    * 参数： 
    * $table_name:表名 
    * $condition:更新条件 
    * $newdata:新的数据记录 
    * $options:更新选择-upsert/multiple 
    * 
    * 返回值： 
    * 成功：true 
    * 失败：false 
    */  
    function update($table_name, $condition, $newdata, $options=array())  
    {  
		
		
        $dbname = $this->curr_db_name;  
        $options['safe'] = 1;  
        if (!isset($options['multiple']))  
        {  
            $options['multiple'] = 0;         
		}  
        try {  

			$bulk = new MongoDB\Driver\BulkWrite;
			$data = $this->mongo->executeQuery($dbname.'.'.$table_name, new MongoDB\Driver\Query($condition), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_PRIMARY_PREFERRED))->toArray();
			if (empty($data[0])) { 
    			$bulk->insert($newdata);
			} else {
				
    			$bulk->update($condition, array('$set' => $newdata),$options); 
			}
			$result = $this->mongo->executeBulkWrite($dbname.'.'.$table_name, $bulk);
			$res = $result->getInsertedCount() || $result->getModifiedCount() ? 1 : 0;
			
			return 1;

        }  
        catch (MongoCursorException $e)  
        {  
            $this->error = $e->getMessage();  
            return false;  
        }         
    }  
  
    /** 
    * 删除记录 
    * 
    * 参数： 
    * $table_name:表名 
    * $condition:删除条件 
    * $options:删除选择-justOne 
    * 
    * 返回值： 
    * 成功：true 
    * 失败：false 
    */  
    public  function remove($table_name, $condition, $options=array())  
    {  
    	error_reporting(0);
    	try {
        	$dbname = $this->curr_db_name;  
        	if (!array_key_exists("limit", $options) || !$options){
        		$options['limit']=0;
        	}
        	//$options['safe'] = 1;  
        
            $bulk = new MongoDB\Driver\BulkWrite;
			//$bulk->delete(['x' => 1], ['limit' => 1]);   // limit 为 1 时，删除第一条匹配数据
			$bulk->delete($condition, $options);   // limit 为 0 时，删除所有匹配数据
			$writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000);
			$result = $this->mongo->executeBulkWrite($dbname.'.'.$table_name, $bulk, $writeConcern);
			
			return $result;
        }  
        catch (MongoCursorException $e)  
        {  
        	$this->error = $e->getMessage();  
 
        }finally {
             return true;
        }          
    }  
  
    /** 
    * 查找记录 
    * 
    * 参数： 
    * $table_name:表名 
    * $query_condition:字段查找条件 
    * $result_condition:查询结果限制条件-limit/sort等 
    * $fields:获取字段 
    * 
    * 返回值： 
    * 成功：记录集 
    * 失败：false 
    */  
    function find($table_name, $query_condition, $result_condition=array(), $fields=array())  
    {  
        $dbname = $this->curr_db_name;  
        $query = new MongoDB\Driver\Query($query_condition, $result_condition);
		$cursor = $this->mongo->executeQuery($dbname.'.'.$table_name, $query); 
		$resault=array();
		foreach ($cursor as $document) {
    		$resault[]=$this->object2array($document);
		}
		return @$resault;

    }  
    //获取表最新ID
    function getByid($table_name,$sort="_id",$where=array())
    {
    	$stk=array("start"=>0,"limit"=>1,"sort"=>array("$sort"=>-1));
    	$rows=$this->find($table_name, $where,$stk);
    
		$lastIds=@$rows[0][$sort];
		
		return @trim(array_pop($lastIds));
    }
	
    /** 
    * 查找一条记录 
    * 
    * 参数： 
    * $table_name:表名 
    * $condition:查找条件 
    * $fields:获取字段 
    * 
    * 返回值： 
    * 成功：一条记录 
    * 失败：false 
    */  
    function findOne($table_name, $condition, $fields=array())  
    {  
	
        $dbname = $this->curr_db_name;
		$query = new MongoDB\Driver\Query($condition, array()); 
		
        $cursor = $this->mongo->executeQuery($dbname.'.'.$table_name, $query, new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_PRIMARY_PREFERRED));
		if($cursor){
			$response = @$cursor->toArray()[0];
			if($response){
				return $this->object2array($response);
			}
		}
		return array();
		
    }  
  
    /** 
    * 获取当前错误信息 
    * 
    * 参数：无 
    * 
    * 返回值：当前错误信息 
    */  
    function getError()  
    {  
        return $this->error;  
    }  
    
    /**
     * 自动添加索引--
     */
    public function atuoEnsuIndex($table_name,$record){
    	if (array_key_exists("status", $record)) {
    		$this->ensureIndex($table_name, array("status"=>1), array('index'=>true));
    	}
    	if (array_key_exists("user_id", $record)) {
    		$this->ensureIndex($table_name, array("user_id"=>1), array('index'=>true));
    	}
    	if (array_key_exists("id", $record)) {
    		$this->ensureIndex($table_name, array("id"=>1), array('index'=>true));
    	}
    	if (array_key_exists("last_update_time", $record)) {
    		$this->ensureIndex($table_name, array("last_update_time"=>1), array('index'=>true));
    	}
    	if (array_key_exists("cat_id", $record)) {
    		$this->ensureIndex($table_name, array("cat_id"=>1), array('index'=>true));
    	}
    	if (array_key_exists("order_sn", $record)) {
    		$this->ensureIndex($table_name, array("order_sn"=>1), array('index'=>true));
    	}
    }
	
	
	private function object_to_array($obj) {
		try {
			error_reporting(0);
			$_arr = is_object($obj) ? get_object_vars($obj) :$obj;
			foreach ($_arr as $key=>$val){
				$val = (is_array($val) || is_object($val)) ? $this->object_to_array($val):$val;
				$arr[$key] = $val;
			}
			if (!$arr){
				return array();
			}
			return $arr;
		}catch (Exception $e){
			
		}finally {
			error_reporting(E_ALL);
		}
	}
	private function object2array($object) {
		return $this->object_to_array($object);
	}
	
    
}  

function newMongoId($id){
	if(empty($id)) return;
	if(is_string($id)){
		if(isset($_GET["test"])){
			var_dump($id);
		}
		return new MongoDB\BSON\ObjectID($id);
	}else{
		return new MongoDB\BSON\ObjectID(array_pop($id));
	}
	
}

function newMongoRegex($Regex,$tag=null){
	$tag??$tag='i';
	if (stripos("regex".$Regex,'/')){
		$Regex=str_replace("/", "", $Regex);
	}
	if (stripos("regex".$Regex,'$')){
		$tag=@preg_replace_callback('/(.+)(\$)+(\w)+/', function ($d){
			$tag=$d[3];
			return $tag;
		}, $Regex);
		if (empty($tag)){
			$tag='i';
		}
		$Regex=str_replace('$', "", $Regex);
		$Regex=str_replace($tag, "", $Regex);
	}
	return new MongoDB\BSON\Regex($Regex, $tag);
}



 /**
require_once($_SERVER['DOCUMENT_ROOT']."//cls_mongodb.php");
$mongo = new mongodbs(); 
$mongo->selectDb("goods");
$mongo->insert("ceibasss", array("id"=>2, "title"=>"asdqw"));
  */ 
?>
